package Day_0131.JVM;

/**
 * @author zxc
 * @date 2023/01/31 21:25
 **/
public class MetaSpace {
    public static void main(String[] args) {
        /**
         * 虚拟机为啥使用元空间来代替永久代呢？
         *
         * 1.方法区 ：（永久代 && 元空间，都是方法区的具体实现）
         * 方法区和堆一样，是各个线程共享的内存区域，它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。
         *
         * 2.永久代
         * 可以说方法区是规范，永久代是Hotspot针对该规范进行的实现。在Java7及以前的版本，方法区都是永久代实现的。
         *
         * 3.元空间
         * 对于Java8，HotSpots取消了永久代，取而代之的是元空间(Metaspace)。
         * 换句话说，就是方法区还是在的，只是实现变了，从永久代变为元空间了。
         *
         * 4.为啥使用元空间来代替永久代
         * （1）永久代的方法区，和堆使用的物理内存是连续的。
         * ===》 即，永久代是存储在堆内存中的;（即，等价于存储在虚拟机内存中;）
         *  「永久代」是通过以下这两个参数配置大小的~
         *  -XX:PremSize：设置永久代的初始大小
         *  -XX:MaxPermSize: 设置永久代的最大值，默认是64M
         *
         * 问题 ：
         * 对于「永久代」，如果动态生成很多class的话，就很可能出现「java.lang.OutOfMemoryError:PermGen space错误」;
         * 因为永久代空间配置有限嘛。最典型的场景是，在web开发比较多jsp页面的时候。
         *
         * （2）JDK8之后，方法区存在于元空间(Metaspace)。
         * ===> 即，元空间是存储在本地内存中，所能够存储的不会受限于虚拟机内存,而是受限于本机内存;
         * 物理内存不再与堆连续，而是直接存在于本地内存中，理论上机器「内存有多大，元空间就有多大」。
         *
         * 通过以下的参数来设置元空间的大小：
         * -XX:MetaspaceSize，初始空间大小，达到该值就会触发垃圾收集进行类型卸载，同时GC会对该值进行调整：
         * 如果释放了大量的空间，就适当降低该值；
         * 如果释放了很少的空间，那么在不超过MaxMetaspaceSize时，适当提高该值。
         * -XX:MaxMetaspaceSize，最大空间，默认是没有限制的。
         * -XX:MinMetaspaceFreeRatio，在GC之后，最小的Metaspace剩余空间容量的百分比，减少为分配空间所导致的垃圾收集
         * -XX:MaxMetaspaceFreeRatio，在GC之后，最大的Metaspace剩余空间容量的百分比，减少为释放空间所导致的垃圾收集
         *
         * ===》
         * 方法区的实现使用元空间代替永久代的原因 ：
         * （1）为了避免OOM异常。
         * （2）因为通常使用PermSize和MaxPermSize设置永久代的大小就决定了永久代的上限，如果使用默认值很容易遇到OOM错误。
         * （3）当使用元空间时，可以加载多少类的元数据就不再由MaxPermSize控制, 而由系统的实际可用空间来控制啦。
         *
         */
    }
}
